package appTool

import (
	"gitee.com/kinwyb/appTools/log"
	"gitee.com/kinwyb/conv"
	"github.com/shima-park/agollo"
)

// ApolloConfig apollo配置中心
type ApolloConfig struct {
	apollo         agollo.Agollo
	apolloHost     string
	appID          string
	groupNamespace string
	watchValue     map[string][]*ConfigWatch
	runWatch       bool
}

func NewApollo(apolloHost string, appID string, groupNamespace string) (*ApolloConfig, error) {
	a, err := agollo.New(apolloHost, appID, agollo.AutoFetchOnCacheMiss(), agollo.FailTolerantOnBackupExists())
	if err != nil {
		return nil, err
	}
	return &ApolloConfig{
		apollo:         a,
		apolloHost:     apolloHost,
		appID:          appID,
		groupNamespace: groupNamespace,
		watchValue:     map[string][]*ConfigWatch{},
	}, nil
}

// Apollo 获取apollo对象
func (a *ApolloConfig) Apollo() agollo.Agollo {
	return a.apollo
}

func (a *ApolloConfig) ReadString(key string, defaultValue string) string {
	if a.apollo != nil {
		ret := a.apollo.Get(key)
		if ret == "" {
			ret = a.apollo.Get(key, agollo.WithNamespace(a.groupNamespace))
		}
		if ret != "" {
			return systemParseEnvStringValue(ret)
		}
	}
	return systemParseEnvStringValue(defaultValue)
}
func (a *ApolloConfig) ReadInt64(key string, defaultValue int64) int64 {
	if a.apollo != nil {
		return conv.ToInt64Default(a.ReadString(key, ""), defaultValue)
	}
	return defaultValue
}
func (a *ApolloConfig) ReadFloat64(key string, defaultValue float64) float64 {
	if a.apollo != nil {
		return conv.ToFloat64Default(a.ReadString(key, ""), defaultValue)
	}
	return defaultValue
}
func (a *ApolloConfig) ReadBool(key string, defaultValue bool) bool {
	if a.apollo != nil {
		return conv.ToBoolDefault(a.ReadString(key, ""), defaultValue)
	}
	return defaultValue
}

// Deprecated: use WatchKey function
func (a *ApolloConfig) Watch() <-chan *agollo.ApolloResponse {
	a.apollo.Start()        //或略监听错误
	return a.apollo.Watch() //监听变化
}

func (a *ApolloConfig) watchRoutine() {
	a.runWatch = true
	defer func() {
		if e := recover(); e != nil {
			log.AppTool.WithField("error", e).Error("apollo变化监听崩溃")
			go a.watchRoutine() //重启线程
		}
	}()
	a.apollo.Start()          //或略监听错误
	watch := a.apollo.Watch() //监听变化
	if watch != nil {
		for {
			resp := <-watch
			for k, v := range resp.NewValue {
				opts := a.watchValue[k]
				oldValue := resp.OldValue[k]
				if len(opts) > 0 {
					for _, opt := range opts {
						if opt.use {
							opt.setValue(v, oldValue)
						}
					}
				}
			}
		}
	}
}

// WatchKey 监听指定键值,返回对象只允许吊用一次set方法
func (a *ApolloConfig) WatchKey(key string) *ConfigWatch {
	watch := &ConfigWatch{
		key: key,
	}
	if a.watchValue == nil {
		a.watchValue = map[string][]*ConfigWatch{}
	}
	a.watchValue[key] = append(a.watchValue[key], watch)
	if !a.runWatch {
		go a.watchRoutine()
	}
	return watch
}
